(function (window){
  // 定义状态值常量
  const PENDING = "pending";
  const FULFILLED = "fulfilled";
  const REJECTED = "rejected";

  /**
   * 构造函数
   * @param  excutor 执行器函数
  */

  /* 
  思路：
    promise对象内部要存储哪些信息?
      1. 状态: pending/fulfilled/rejected  ==> state
      2. 结果数据: undefined/value/reason  ==> date
      3. 保存待处理回调的数组: [{resolved () {}, rejected () {}}, {resolved () {}, rejected () {}}] => callbacks
   
      在构造函数中, 会立即同步调用执行器函数, 并传入resolve和reject 两个函数

      resolve函数
        参数: value
        作用: 将promise的状态改为resolved, 将value保存到date
      reject函数
        参数: reason
        作用: 将promise的状态改为rejected, 将reason保存到date
  */
  function Promise(excutor) {
    // 初始化3个属性
    // 1.状态：pending/fulfilled/rejected ==>state存储
    this.state = PENDING;
    // 2.结果数据：undefined/value/reason ==>date存储
    this.date = undefined;
    // 3.保存待处理的回调函数的数组：例[{resolved(){},reject(){}},{resolved(){},reject(){}}]
    this.callbacks = [];

    // 保存this指向（作用：方便后续使用）
    const that = this;

    /*
    resolve函数
        参数: value
        作用: 将promise的状态改为resolved, 将value保存到date
    */
    function resolve(value) {
      // 只有状态为 pending 才会往下执行 成功/失败是没必要执行resolve/reject
      if (that.state !== PENDING) {
        return;
      }
      // 修改promise对象状态为成功
      that.state = FULFILLED;
      // 保存调用resolve对应的值
      that.date = value;
      // 异步执行callbacks中所有成功的回调
      // 我们没办法直接向微队列中添加回调 => 只能用宏队列了 setTimeout
      // 这里是为了防止异步resolve()调用
      if (that.callbacks.length > 0) {
        setTimeout(() => {
          that.callbacks.forEach((callbackobj) => callbackobj.resolved(value));
        }, 0);
      }
    }

    /*
    reject函数
        参数: renson
        作用: 将promise的状态改为reject, 将renson保存到date
    */

    function reject(reason) {
      // 只有状态为 pending 才会往下执行 成功/失败是没必要执行resolve/reject
      if (that.state !== PENDING) {
        return;
      }
      // 修改promise对象状态为成功
      that.state = REJECTED;
      // 保存调用resolve对应的值
      that.date = reason;
      // 异步执行callbacks中所有成功的回调
      // 我们没办法直接向微队列中添加回调 => 只能用宏队列了 setTimeout
      // 这里是为了防止异步resolve()调用
      if (that.callbacks.length > 0) {
        setTimeout(() => {
          that.callbacks.forEach((callbackobj) => callbackobj.rejected(reason));
        }, 0);
      }
    }

    // 捕获执行器抛出的错误
    // 因为在原promise传入resolve和reject是直接就会执行所以这里我们也要写这个特点
    try {
      /*  在构造函数中, 会立即同步调用执行器函数, 并传入resolve和reject 两个函数 */
      excutor(resolve,reject);
    } catch (error) {
      // 将当前promise变为rejected, reason为error
      reject(error);
    }

  }

  /* ------------------实例的方法--是挂在到原型上的--------------------------------------------------------------------- */
  /**
   * 指定成功和失败的回调, 并返回一个新的promise
   * @param {*} onResolved 成功的回调 => 用于得到成功的value
   * @param {*} onRejected 失败的回调 => 用于得到失败的reason
   */
  /* 
  思路：
   then返回的promise的结果由什么决定
		简单表达: 由then指定的回调执行的结果决定
      返回promise  ==> 得到并改为它的状态
      返回非promise  ==> 变为成功状态
      抛出错误   ==> try---catch  => 变为失败状态
  */
  Promise.prototype.then = function (onResolved, onRejected){
    const that = this; // 保存this指向（作用：方便后续使用）
    // 如果onResolved不是函数, 指定一个默认函数, 向下传递value
    onResolved = typeof onResolved==='function' ? onResolved : value => value
    // 如果onRejected不是函数, 指定一个默认函数, 向下传递reason
    onRejected = typeof onRejected==='function' ? onRejected : reason => {throw reason}

    return new Promise((resolve,reject)=>{
      /**
       * 调用指定成功/失败的回调函数, 根据执行结果更新返回的promies的状态
       * @param {*} callback 
      */

     // 这里封装是因为后续操作发现都是一样的 
     function cb(callback) {
      try {
        const result = callback(that.date); // 获取promise对象对象传入的值
        if (result instanceof Promise) { // 第一种:传入了一个promise对象
          // 此时result就是一个 promise对象 （需要获得result的状态 并且返回回去）
          result.then(value =>{
            resolve(value);
          },reason=>{
            reject(reason);
          })
        }else{ // 第二种:传入了一个非promise对象（普通值）
          resolve(result);
        }
      } catch (error) { // 第三种:传入了一个错误
        reject(error);
      }
     }
    // 如果当前是成功的, 异步执行onResolved
    if (that.state===FULFILLED) {
      setTimeout(()=>{
        cb(onResolved);
      },0)
    } else if (that.state===REJECTED) { // 如果当前是失败的, 异步执行onRejacted
      setTimeout(()=>{
        cb(onRejected);
      },0)
    }else{ // 如果是等待的 就把当前的onResolved和onRejected保存起来 等状态变化 再重新执行
      that.callbacks.push({
        resolved: () => cb(onResolved),
        rejected: () => cb(onRejected)
      })
    }
    })
  }
  /**
   * 思路：
   * 指定失败的回调, 并返回一个新的promise
   * 本质是then方法的语法糖(简洁语法)
   * then(value => value, onRejected)
   * @param {*} onRejected 失败的回调 => 用于得到失败的reason
  */
  Promise.prototype.catch = function (onRejected){
    return this.then(value => value , onRejected)
  }
  /*
  finally(onFinal):
     无论当前promise是成功还是失败, onFinal都会执行, onFinal不接收参数,
     finally也是返回一个新的promise, 结果状态由当前promise的结果状态决定
  */ 
  Promise.prototype.finally = function (onFinal){
    const that = this;
    return new Promise((resolve, reject) => {
      // 得到当前promise成功或失败的结果
      // 无论成功还是失败都调用onFinal
      // 如果成功, 将返回的promise变为成功
      // 如果失败, 将返回的promise变为失败
      that.then(value =>{
        onFinal();
        resolve(value);
      },reason =>{
        onFinal();
        reject(reason);
      })
    })
  }
  /* ------------------静态方法--是Promise本身有的--------------------------------------------------------------------- */
  /*
   1. resolve():返回一个成功的promise, value为指定的value可能是非promise, 也可能是promise
   2. reject():返回一个失败的promise, reason为指定的reason
   3. all():返回一个promise, 如果promises都成功, 它才成功, 成功的value为所有value组成的数组, 只要有一个失败, 那它就失败了
   4. race():返回一个promise, 由第一个完成的promie来决定它的结果
   5. allSettled():返回一个promise, 当所有promise都完成时它就成功, value值为所有promise的value或reason组成的数组
   */
  //  1. resolve():返回一个成功的promise, value为指定的value可能是非promise, 也可能是promise
  Promise.resolve = function (value) {
    return new Promise((resolve,reject)=>{
      if (value instanceof Promise) {
        // console.log(value);
        value.then(value =>{
          resolve(value);
        },reason =>{
          reject(reason);
        })
      }else{
        resolve(value)
      }
    })
  }
  // 2. reject():返回一个失败的promise, reason为指定的reason
  Promise.reject = function (reason){
    return new Promise((resolve, reject) => {
      reject(reason);
    })
  }
  // 3. all():返回一个promise, 如果promises都成功, 它才成功, 成功的value为所有value组成的数组, 只要有一个失败, 那它就失败了
  Promise.all = function (arr){
    return new Promise((resolve, reject) => {
      const promiseArr = []; // 保存成功的value为所有value
      let num = 0; // 计数器
      arr.forEach((p,idx)=>{
        p.then(value =>{
          promiseArr[idx].push = value;
          num++;
          if (arr.length === num) {
            resolve(promiseArr);
          }
        },reason=>{
          reject(reason)
        })
      })
    })
  }
  // 4. race():返回一个promise, 由第一个完成的promie来决定它的结果
  Promise.race = function (arr){
    return new Promise((resolve, reject) => {
      arr.forEach((p)=>{
        p.then(value =>{
          resolve(value);
        },reason=>{
          reject(reason)
        })
      })
    })
  }
  // 5. allSettled():返回一个promise, 当所有promise都完成时它就成功, value值为所有promise的value或reason组成的数组
  Promise.allSettled = function (arr){
    const promiseArr = []; // 保存成功的value为所有value
    let num = 0; // 计数器
    return new Promise((resolve, reject) => {
     
      arr.forEach((p,idx)=>{
        p.then(value =>{
          promiseArr[idx] = {status: FULFILLED, value}
          num++;
          if (arr.length === num) {
            resolve(promiseArr);
          }
        },reason=>{
          promiseArr[idx] = {status: REJECTED, reason}
          num++;
          if (arr.length === num) {
            resolve(promiseArr);
          }
        })
      })
    })
  }
  // 直接挂在到window上
  window.Promise = Promise;
})(window);
